<?php

namespace services\rbac;

use api\modules\v1\forms\rbac\MenuForm;
use common\components\Service;
use common\helpers\CommonHelper;
use common\models\rbac\Action;
use common\models\rbac\Menu;
use common\models\rbac\Module;
use common\models\rbac\RolePermission;

/**
 * Class MenuService
 * @package services\rbac
 */
class MenuService extends Service
{
    /**
     * 根据ID查找菜单信息
     *
     * @param int $id
     * @return Menu|null
     */
    public function findById(int $id): ?Menu
    {
        return Menu::find()->where(['id' => $id])->one();
    }

    /**
     * 菜单信息
     *
     * @param array $condition
     * @return Menu|null
     */
    public function findInfo(array $condition = []): ?Menu
    {
        $query = Menu::find();

        isset($condition['name']) && $query->andWhere(['name' => $condition['name']]);
        isset($condition['status']) && $query->andWhere(['status' => $condition['status']]);
        isset($condition['parent_menu_id']) && $query->andWhere(['parent_menu_id' => $condition['parent_menu_id']]);
        isset($condition['module_id']) && $query->andWhere(['module_id' => $condition['module_id']]);

        return $query->one();
    }

    /**
     * 获取列表
     * @param array $condition
     * @return array|\yii\db\ActiveRecord[]
     */
    public function findList(array $condition = [])
    {
        $query = Menu::find();

        isset($condition['id']) && $query->andWhere(['id' => $condition['id']]);
        isset($condition['status']) && $query->andWhere(['status' => $condition['status']]);

        // orderBy
        isset($condition['orderBy']) && $query->orderBy($condition['orderBy']);

        return $query->asArray()->all();
    }

    /**
     * 获取菜单权限
     *
     * @return array|\yii\db\ActiveRecord[]
     */
    public function getInnerActionList()
    {
        return Menu::find()
            ->select([
                'a.id', 'a.name', 'a.parent_menu_id', 'a.module_id',
                'GROUP_CONCAT(b.id ORDER BY b.sort,b.id ASC) AS action_ids', 'GROUP_CONCAT(b.name ORDER BY b.sort,b.id ASC) AS action_names'
            ])
            ->alias('a')
            ->leftJoin(Action::tableName() . ' AS b', 'b.menu_id = a.id AND b.status = ' . Action::STATUS_ENABLE)
            ->where([
                'a.status' => Menu::STATUS_ENABLE
            ])
            ->groupBy('a.id')
            ->orderBy(['a.sort' => SORT_ASC, 'a.id' => SORT_ASC])
            ->asArray()
            ->all();
    }

    /**
     * 格式化菜单权限
     *
     * @param array $data
     * @param int $pid
     * @param array $hasAuth 已有权限 [
     *      'menu' => [1,2,3...],// 菜单IDs
     *      'action' => [1,2,3...]// 动作IDs
     * ]
     * @return array
     */
    public function getInnerActionListFormat(array $data = [], $pid = 0, array $hasAuth = [])
    {
        // 已拥有权限
        $menuAuth = $hasAuth['menu'] ?? [];
        $actionAuth = $hasAuth['action'] ?? [];

        $list = [];
        foreach ($data as $row) {
            if ($row['parent_menu_id'] != $pid) {
                continue;
            }

            // 子菜单
            $children = $this->getInnerActionListFormat($data, $row['id'], $hasAuth);
            $children[$row['module_id']] = $children[$row['module_id']] ?? [];

            // 动作列表
            $actionIds = $row['action_ids'] ? explode(',', $row['action_ids']) : [];
            $actionNames = $row['action_names'] ? explode(',', $row['action_names']) : [];
            foreach ($actionIds as $k => $v) {
                $children[$row['module_id']][] = [
                    'value' => $v,
                    'title' => $actionNames[$k],
                    'permission_type' => RolePermission::PERMISSION_TYPE_ACTION,
                    'expand' => false,
                    'checked' => in_array($v, $actionAuth),
                ];
            }

            // 父菜单
            $item = [
                'value' => $row['id'],
                'title' => $row['name'],
                'permission_type' => RolePermission::PERMISSION_TYPE_MENU,
                'expand' => !empty($children[$row['module_id']]),
                // 'checked' => in_array($row['id'], $menuAuth),
                // 'children' => $children,
            ];
            // 底层返回checked属性
            if (empty($children[$row['module_id']])) {
                $item['checked'] = in_array($row['id'], $menuAuth);
            }
            $item['children'] = $children[$row['module_id']];

            $list[$row['module_id']][] = $item;
        }

        return $list;
    }

    /**
     * 菜单列表
     *
     * @param array $params
     * @param int $page
     * @param int $pageSize
     * @return array
     */
    public function getListPage(array $params = [], int $page = 0, int $pageSize = 0)
    {
        $query = Menu::find()->alias('a')
            ->select([
                'a.*',
                'b.name AS module_name',
                'c.name AS pname'
            ])
            ->leftJoin(Module::tableName(). ' AS b', 'b.id = a.module_id')
            ->leftJoin(Menu::tableName() . ' AS c', 'c.id = a.parent_menu_id')
            ->where(['a.status' => [Menu::STATUS_INVALID, Menu::STATUS_ENABLE]]);

        $order = ['a.status' => SORT_DESC, 'a.sort' => SORT_ASC, 'a.id' => SORT_ASC];

        return $this->getListPageRes($query, $page, $pageSize, $order);
    }

    /**
     * 格式化菜单列表
     *
     * @param array $data
     * @return array
     */
    public function getListPageFormat(array $data = [])
    {
        $list = [];
        foreach ($data as $row) {
            $list[] = [
                'id' => $row['id'],
                'parent_menu_id' => $row['parent_menu_id'],
                'module_id' => $row['module_id'],
                'name' => $row['name'],
                'pname' => $row['pname'] ? $row['pname'] : '',
                'module_name' => $row['module_name'] ? $row['module_name'] : '',
                'flag' => $row['flag'],
                'url' => $row['url'],
                'class_style' => $row['class_style'],
                'sort' => $row['sort'],
                'status' => $row['status'],
                'status_str' => Menu::$statuss[$row['status']],
                'created_at_str' => $row['created_at'] ? date('Y-m-d H:i:s', $row['created_at']) : '',
            ];
        }

        return $list;
    }

    /**
     * 格式化菜单数据
     *
     * @param array $data 查询结果【getList】
     * @param int $pid 菜单parent_menu_id
     * @param int $checkId 选中ID
     * @return array
     */
    public function getListFormat(array $data, int $pid = 0, int $checkId = 0)
    {
        $list = [];
        foreach ($data as $row) {
            if ($row['parent_menu_id'] != $pid) {
                continue;
            }

            // 是否选中
            $checked = $checkId != 0 && ($checkId == $row['id'] || $checkId == $row['parent_menu_id']) ? true : false;

            // 子菜单
            $children = $this->getListFormat($data, $row['id'], $checkId);

            $item = [
                'value' => $row['id'],
                'title' => $row['name'],
                'checked' => $checked,
                'expand' => $children ? true : false,
                'children' => $children,
            ];

            $list[] = $item;
        }

        return $list;
    }

    /**
     * 格式化模块菜单数据
     *
     * @param array $data 查询结果【getList】
     * @param int $pid 菜单parent_menu_id
     * @param int $checkId 选中ID
     * @return array
     */
    public function getListModuleFormat(array $data, int $pid = 0, int $checkId = 0)
    {
        $list = [];
        foreach ($data as $row) {
            if ($row['parent_menu_id'] != $pid) {
                continue;
            }

            // 是否选中
            $checked = $checkId != 0 && ($checkId == $row['id'] || $checkId == $row['parent_menu_id']) ? true : false;

            // 子菜单
            $children = $this->getListModuleFormat($data, $row['id'], $checkId);

            $item = [
                'value' => $row['id'],
                'title' => $row['name'],
                'checked' => $checked,
                'expand' => $children ? true : false,
                'children' => $children[$row['module_id']] ?? [],
            ];

            $list[$row['module_id']][] = $item;
        }

        return $list;
    }

    /**
     * 新增菜单
     *
     * @param MenuForm $model
     * @return array|mixed
     */
    public function create(MenuForm $model)
    {
        try {
            // 1.新增菜单
            $menu = new Menu();
            $menu->parent_menu_id = $model->parent_menu_id;
            $menu->module_id = $model->module_id;
            $menu->name = $model->name;
            $menu->url = $model->url;
            $menu->class_style = $model->class_style;
            $menu->status = $model->status;
            $menu->sort = $model->sort;
            $menu->save();

            return ['id' => $menu->id];
        } catch (\Exception $e) {
            return CommonHelper::api(422, $e->getMessage());
        }
    }

    /**
     * 编辑菜单
     *
     * @param MenuForm $model
     * @return array|mixed
     */
    public function edit(MenuForm $model)
    {
        try {
            // 1.更新菜单
            $attributes = [
                'parent_menu_id' => $model->parent_menu_id,
                'module_id' => $model->module_id,
                'name' => $model->name,
                'url' => $model->url,
                'class_style' => $model->class_style,
                'status' => $model->status,
                'sort' => $model->sort,
            ];
            Menu::updateAll($attributes, ['id' => $model->id]);

            return ['id' => $model->id];
        } catch (\Exception $e) {
            return CommonHelper::api(422, $e->getMessage());
        }
    }

    /**
     * 删除菜单
     *
     * @param MenuForm $model
     * @return array|mixed
     */
    public function delete(MenuForm $model)
    {
        try {
            // 1.更新菜单
            $attributes = [
                'status' => Menu::STATUS_DELETE,
            ];
            Menu::updateAll($attributes, ['id' => $model->id]);

            return ['id' => $model->id];
        } catch (\Exception $e) {
            return CommonHelper::api(422, $e->getMessage());
        }
    }

    /**
     * 编辑菜单状态
     *
     * @param MenuForm $model
     * @return array|mixed
     */
    public function editStatus(MenuForm $model)
    {
        try {
            // 1.更新菜单
            $attributes = [
                'status' => $model->status,
            ];
            Menu::updateAll($attributes, ['id' => $model->id]);

            return ['id' => $model->id];
        } catch (\Exception $e) {
            return CommonHelper::api(422, $e->getMessage());
        }
    }
}
